package com.hzbank.qwencode.service;

import com.hzbank.qwencode.config.QwencodeConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.function.Consumer;

/**
 * QwenCode 服务类
 * 提供接口来调用qwencode命令行工具进行文本编码
 */
@Service
@Slf4j
public class QwencodeService implements InitializingBean {

    private final QwencodeConfig config;
    private String qwenCommandPath;
    private final String osType = System.getProperty("os.name").toLowerCase();
    private final ExecutorService executorService = Executors.newCachedThreadPool();

    @Autowired
    public QwencodeService(QwencodeConfig config) {
        this.config = config;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化时查找并验证qwen命令
        log.info("尝试初始化qwencode服务...");
        try {
            this.qwenCommandPath = findQwenCommand();
            validateQwenCommand();
            log.info("✅ qwencode服务已初始化，路径: {}", qwenCommandPath);
        } catch (Exception e) {
            log.error("❌ qwencode服务初始化失败: {}", e.getMessage());
            throw new RuntimeException("无法初始化qwencode服务，请确保qwen命令已安装并在系统PATH中", e);
        }
    }

    /**
     * 查找qwen命令路径
     */
    private String findQwenCommand() throws IOException {
        String command = config.getQwenCommand();
        
        // 在Windows上尝试不同的扩展名
        if (osType.contains("win")) {
            String[] extensions = {".exe", ".cmd", ".bat", ""};
            for (String ext : extensions) {
                String cmdWithExt = command + ext;
                String path = findExecutable(cmdWithExt);
                if (path != null) {
                    log.info("✅ 找到{}命令: {}", command, path);
                    return path;
                }
            }
        } else {
            // 在Unix/Linux/Mac上
            String path = findExecutable(command);
            if (path != null) {
                log.info("✅ 找到{}命令: {}", command, path);
                return path;
            }
        }
        
        throw new FileNotFoundException(command + "命令未在系统PATH中找到");
    }

    /**
     * 在系统PATH中查找可执行文件
     */
    private String findExecutable(String command) {
        String[] paths = System.getenv("PATH").split(File.pathSeparator);
        for (String path : paths) {
            File file = new File(path, command);
            if (file.exists() && file.canExecute()) {
                return file.getAbsolutePath();
            }
        }
        return null;
    }

    /**
     * 验证qwen命令是否可用
     */
    private void validateQwenCommand() {
        try {
            ProcessBuilder pb;
            if (osType.contains("win")) {
                // 在Windows上使用PowerShell
                pb = new ProcessBuilder(
                        "powershell",
                        "-ExecutionPolicy", "Bypass",
                        "&", String.format("\"%s\" --version", qwenCommandPath)
                );
            } else {
                pb = new ProcessBuilder(qwenCommandPath, "--version");
            }
            
            pb.redirectErrorStream(true);
            Process process = pb.start();
            
            // 读取输出
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            // 等待进程完成，但设置超时
            boolean finished = process.waitFor(config.getCommandValidationTimeout(), TimeUnit.SECONDS);
            if (!finished) {
                process.destroy();
                log.warn("⏱️ {}命令验证超时 (超过{}秒)", config.getQwenCommand(), config.getCommandValidationTimeout());
            } else if (process.exitValue() == 0) {
                String outputStr = output.toString().trim();
                log.info("✅ qwencode命令验证成功: {}", qwenCommandPath);
                log.info("📄 版本信息: {}", outputStr.length() > 100 ? outputStr.substring(0, 100) + "..." : outputStr);
            } else {
                log.warn("⚠️ qwencode命令验证失败，退出码: {}", process.exitValue());
                log.warn("ℹ️  输出: {}", output.toString().trim().isEmpty() ? "无" : output.toString().trim());
            }
        } catch (Exception e) {
            log.warn("⚠️ qwencode命令验证过程中出现错误: {}", e.getMessage());
            log.debug("详细错误", e);
        }
    }

    /**
     * 编码文本（同步方法）
     */
    public String encodeText(String text, Map<String, Object> encodingParams, String workingDirectory) throws Exception {
        log.debug("🔄 收到编码请求: 文本长度={}, 参数={}", text.length(), encodingParams);
        
        Future<String> future = executorService.submit(() -> {
            try {
                return executeCommand(text, workingDirectory);
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        });
        
        try {
            return future.get(config.getCommandExecutionTimeout(), TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            future.cancel(true);
            throw new TimeoutException(config.getTimeoutErrorMessage());
        } catch (CompletionException e) {
            throw (Exception) e.getCause();
        }
    }

    /**
     * 流式编码文本
     */
    public void encodeTextStream(String text, Map<String, Object> encodingParams, 
                               String workingDirectory, Consumer<String> chunkConsumer) throws Exception {
        log.debug("🌊 接收到流式编码请求: {}...", text.length() > 50 ? text.substring(0, 50) + "..." : text);
        
        // 先执行命令获取完整结果
        String result = encodeText(text, encodingParams, workingDirectory);
        
        // 模拟流式返回
        int chunkSize = config.getStreamChunkSize();
        for (int i = 0; i < result.length(); i += chunkSize) {
            int end = Math.min(i + chunkSize, result.length());
            String chunk = result.substring(i, end);
            chunkConsumer.accept(chunk);
            
            // 模拟延迟
            Thread.sleep((long) (config.getStreamSimulationDelay() * 1000));
        }
    }

    /**
     * 执行命令行工具
     */
    private String executeCommand(String text, String workingDirectory) throws Exception {
        String uniqueId = UUID.randomUUID().toString().substring(0, 8);
        Path tempDir = Files.createTempDirectory(config.getTempFilePrefix());
        
        try {
            // 创建输入文件
            Path inputFile = tempDir.resolve(config.getTempFilePrefix() + "input_" + uniqueId + ".txt");
            Files.write(inputFile, text.getBytes(StandardCharsets.UTF_8));
            
            // 验证工作目录
            File cwd = null;
            if (workingDirectory != null) {
                cwd = new File(workingDirectory);
                if (!cwd.exists() || !cwd.isDirectory()) {
                    log.warn("⚠️ 指定的工作目录不存在或不是目录: {}", workingDirectory);
                    cwd = null;
                } else {
                    log.debug("📁 使用指定工作目录: {}", cwd.getAbsolutePath());
                }
            }
            
            if (osType.contains("win")) {
                return executeWindowsCommand(inputFile, cwd, uniqueId);
            } else {
                return executeUnixCommand(inputFile, cwd);
            }
        } finally {
            // 清理临时目录
            try {
                Files.walk(tempDir)
                     .map(Path::toFile)
                     .forEach(File::delete);
            } catch (Exception e) {
                log.warn("⚠️ 清理临时文件失败: {}", e.getMessage());
            }
        }
    }

    /**
     * 在Windows上执行命令
     */
    private String executeWindowsCommand(Path inputFile, File workingDirectory, String uniqueId) throws Exception {
        // 创建批处理文件
        Path batFile = inputFile.getParent().resolve(config.getTempFilePrefix() + "run_" + uniqueId + ".bat");
        StringBuilder batContent = new StringBuilder();
        
        // 设置UTF-8代码页
        batContent.append(String.format("@chcp %s > nul\n", config.getWindowsCodepage()));
        
        // 切换到工作目录
        if (workingDirectory != null) {
            batContent.append(String.format("@cd \"%s\"\n", workingDirectory.getAbsolutePath()));
        }
        
        // 执行命令
        batContent.append(String.format("@type \"%s\" | \"%s\"", 
                inputFile.toAbsolutePath(), qwenCommandPath));
        
        // 添加命令参数
        for (String arg : config.getQwenCommandArgs()) {
            batContent.append(" " + arg);
        }
        
        Files.write(batFile, batContent.toString().getBytes(StandardCharsets.UTF_8));
        
        // 执行批处理文件
        ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", batFile.toAbsolutePath().toString());
        pb.redirectErrorStream(true);
        pb.environment().put("PYTHONIOENCODING", "utf-8");
        
        if (workingDirectory != null) {
            pb.directory(workingDirectory);
        }
        
        return executeProcess(pb);
    }

    /**
     * 在Unix/Linux/Mac上执行命令
     */
    private String executeUnixCommand(Path inputFile, File workingDirectory) throws Exception {
        List<String> command = new ArrayList<>();
        command.add("sh");
        command.add("-c");
        
        StringBuilder cmdBuilder = new StringBuilder();
        cmdBuilder.append("cat '").append(inputFile).append("' | '").append(qwenCommandPath).append("'");
        
        for (String arg : config.getQwenCommandArgs()) {
            cmdBuilder.append(" '").append(arg).append("'");
        }
        
        command.add(cmdBuilder.toString());
        
        ProcessBuilder pb = new ProcessBuilder(command);
        pb.redirectErrorStream(true);
        pb.environment().put("LC_ALL", "zh_CN.UTF-8");
        pb.environment().put("LANG", "zh_CN.UTF-8");
        
        if (workingDirectory != null) {
            pb.directory(workingDirectory);
        }
        
        return executeProcess(pb);
    }

    /**
     * 执行进程并获取输出
     */
    private String executeProcess(ProcessBuilder pb) throws Exception {
        Process process = pb.start();
        
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
        }
        
        // 等待进程完成
        int exitCode = process.waitFor();
        
        if (exitCode != 0) {
            log.error("❌ 命令执行失败，退出码: {}", exitCode);
            throw new RuntimeException("命令执行失败，退出码: " + exitCode);
        }
        
        log.debug("✅ 命令执行成功，输出长度: {}", output.length());
        return output.toString();
    }
}